/*This file is part of jasmo.

jasmo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

jasmo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with jasmo.  If not, see <http://www.gnu.org/licenses/>.*/

package com.lab9.jasmo.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import com.lab9.jasmo.domain.IMonitoredService;
import com.lab9.jasmo.domain.impl.serviceMonitors.DummyErrorWorkingMonitor;
import com.lab9.jasmo.domain.impl.serviceMonitors.DummyWorkingMonitoredService;
import com.thoughtworks.xstream.XStreamer;

/**
 * this is a monitoring service configurator that reads XML formatted data and
 * spits out the respective configured devices. It can also be used to export a
 * configuration made to the respective XML format.
 * 
 * @author dpsenner@gmail.com
 * 
 */
public class MonitoringServiceConfigurator {
	private static final Logger logger = Logger.getLogger(MonitoringServiceConfigurator.class);
	
	/**
	 * reads the configuration from a file named "jasmo.configuration"
	 * stored in the working path of the application.
	 * 
	 * @return
	 * @throws ConfigurationFailedException
	 */
	public List<IMonitoredService> ReadConfig() throws ConfigurationFailedException {
		try {
			File file = GetDefaultConfigFile();
			GenerateDummyData(file);
			FileInputStream stream = new FileInputStream(file);
			try {
				return ReadConfig(stream);
			} finally {
				try {
					stream.close();
				} catch (IOException e) {
					throw new ConfigurationFailedException(e);
				}
			}
		} catch (FileNotFoundException e) {
			throw new ConfigurationFailedException(e);
		}
	}

	/**
	 * @param file
	 * @throws ConfigurationFailedException
	 */
	private void GenerateDummyData(File file) throws ConfigurationFailedException {
		if(!file.exists()) {
			logger.info("generating dummy data and writing it to file " + file.getAbsolutePath());
			// TODO remove this dummy generation process in future versions
			List<IMonitoredService> list = new LinkedList<IMonitoredService>();
			list.add(new DummyWorkingMonitoredService());
			list.add(new DummyErrorWorkingMonitor());
			StoreConfig(list);
			logger.info("generated dummy data and wrote it to file " + file.getAbsolutePath());
		} else {
			logger.info("generate of dummy data not needed; file " + file.getAbsolutePath() + " exists");
		}
	}
	
	/**
	 * writes the configuration to a file named "jasmo.configuration" in the working
	 * path of the application.
	 * @param config
	 * @throws ConfigurationFailedException
	 */
	public void StoreConfig(List<IMonitoredService> config) throws ConfigurationFailedException {
		try {
			FileOutputStream stream = new FileOutputStream(GetDefaultConfigFile());
			try {
				StoreConfig(stream, config);
			} finally  {
				try {
					stream.close();
				} catch (IOException e) {
					throw new ConfigurationFailedException(e);
				}
			}
		} catch (FileNotFoundException e) {
			throw new ConfigurationFailedException(e);
		}
	}

	/**
	 * retrieves the default jasmo configuration file.
	 * @return
	 */
	private File GetDefaultConfigFile() {
		return new File("jasmo.configuration");
	}

	/**
	 * reads a configuration from a arbitrary input stream.
	 * 
	 * @param in
	 * @return
	 * @throws ConfigurationFailedException 
	 */
	@SuppressWarnings("unchecked")
	private List<IMonitoredService> ReadConfig(InputStream in) throws ConfigurationFailedException {
		try {
			return (List<IMonitoredService>) new XStreamer().fromXML(new InputStreamReader(in));
		} catch (ObjectStreamException e) {
			throw new ConfigurationFailedException(e);
		} catch (IOException e) {
			throw new ConfigurationFailedException(e);
		} catch (ClassNotFoundException e) {
			throw new ConfigurationFailedException(e);
		} catch (ClassCastException e) {
			throw new ConfigurationFailedException(e);
		}
	}
	
	private void StoreConfig(OutputStream out, List<IMonitoredService> config) throws ConfigurationFailedException {
		try {
			new XStreamer().toXML(XStreamConfigurator.GetXStream(), config, new OutputStreamWriter(out));
		} catch (ObjectStreamException e) {
			throw new ConfigurationFailedException(e);
		} catch (IOException e) {
			throw new ConfigurationFailedException(e);
		}
	}
}
